
package com.tfq.cloud

import com.tfq.cloud.auth.config.JwtConfig
import org.pac4j.jwt.config.encryption.SecretEncryptionConfiguration
import org.pac4j.jwt.config.signature.RSASignatureConfiguration
import org.pac4j.jwt.profile.JwtGenerator
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean
import reactor.core.publisher.Mono
import java.security.KeyFactory
import java.security.KeyPair
import java.security.PrivateKey
import java.security.spec.PKCS8EncodedKeySpec
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi

/**
 * Spring Boot 应用程序的主类
 * 启用 Spring Boot 的自动配置和组件扫描
 * 启用 Spring Cache 支持
 */
@SpringBootApplication
@EnableCaching
class Application {

    @Autowired
    private lateinit var jwtConfig: JwtConfig

    companion object {
        private val logger = LoggerFactory.getLogger(Application::class.java)
    }

    /**
     * 创建并返回一个 JwtGenerator 实例
     * 用于生成 JWT 令牌
     *
     * @return JwtGenerator 实例
     * @throws IllegalStateException 如果 JwtGenerator 初始化失败
     */
    @Bean
    fun generator(): JwtGenerator {
        validateJwtConfig()

        // 使用单例模式缓存 KeyFactory 实例
        val keyFactory = getKeyFactory(jwtConfig.algorithm)

        return Mono.fromCallable { decodePrivateKey(keyFactory, jwtConfig.privateKey) }
            .map { privateKey ->
                JwtGenerator(
                    RSASignatureConfiguration(KeyPair(null, privateKey)),
                    SecretEncryptionConfiguration(jwtConfig.encryptionKey)
                )
            }
            .doOnError { throwable ->
                logger.error("生成 JwtGenerator 失败：私钥可能无效或加密密钥缺失", throwable)
            }
            .onErrorMap { throwable ->
                IllegalStateException("JwtGenerator 初始化失败: ${throwable.message}", throwable)
            }
            .blockOptional()
            .orElseThrow { IllegalStateException("JwtGenerator 初始化失败: 私钥或加密密钥无效") }
    }

    /**
     * 解码并验证私钥
     *
     * @param keyFactory KeyFactory 实例
     * @param privateKeyBase64 Base64 编码的私钥字符串
     * @return 解码后的 PrivateKey 实例
     * @throws IllegalArgumentException 如果私钥格式不正确
     */
    @OptIn(ExperimentalEncodingApi::class)
    private fun decodePrivateKey(keyFactory: KeyFactory, privateKeyBase64: String): PrivateKey {
        if (privateKeyBase64.isBlank()) {
            throw IllegalArgumentException("私钥不能为空")
        }

        return try {
            val decodedBytes = Base64.Default.decode(privateKeyBase64.encodeToByteArray())
            keyFactory.generatePrivate(PKCS8EncodedKeySpec(decodedBytes))
        } catch (e: IllegalArgumentException) {
            logger.warn("私钥解码失败，可能格式不正确 (Base64 长度: ${privateKeyBase64.length})", e)
            throw IllegalArgumentException("私钥解码失败，可能格式不正确", e)
        } catch (e: Exception) {
            logger.warn("私钥解码失败，未知错误 (Base64 长度: ${privateKeyBase64.length})", e)
            throw IllegalArgumentException("私钥解码失败，未知错误", e)
        }
    }

    /**
     * 获取 KeyFactory 单例实例
     *
     * @param algorithm 加密算法名称
     * @return KeyFactory 实例
     * @throws IllegalArgumentException 如果算法无效
     */
    private fun getKeyFactory(algorithm: String): KeyFactory {
        return try {
            KeyFactory.getInstance(algorithm)
        } catch (e: Exception) {
            logger.error("无法获取 KeyFactory 实例，算法无效: $algorithm", e)
            throw IllegalArgumentException("算法无效: $algorithm", e)
        }
    }

    /**
     * 验证 JwtConfig 配置项的有效性
     *
     * @throws IllegalArgumentException 如果配置项无效
     */
    private fun validateJwtConfig() {
        if (jwtConfig.algorithm.isBlank()) {
            throw IllegalArgumentException("JWT 配置中算法不能为空")
        }
        if (jwtConfig.privateKey.isBlank()) {
            throw IllegalArgumentException("JWT 配置中私钥不能为空")
        }
        if (jwtConfig.encryptionKey.isBlank()) {
            throw IllegalArgumentException("JWT 配置中加密密钥不能为空")
        }
        if (jwtConfig.encryptionKey.length < 16) {
            throw IllegalArgumentException("加密密钥长度不足，至少需要 16 个字符")
        }
    }
}

/**
 * 程序的入口点
 * 启动 Spring Boot 应用程序
 */
fun main(args: Array<String>) {
    runApplication<Application>(*args)
}